home *** CD-ROM | disk | FTP | other *** search
- # AlphaTcl - core Tcl engine
-
- namespace eval app {}
-
- proc app::ensureRunning {sig {in_front 0}} {
- # See if a process w/ any of the acceptable
- # sigs already running.
- if {[app::isRunning [list $sig] name]} {
- if {$in_front} {switchTo '$sig'}
- return $name
- }
- if {[catch {nameFromAppl $sig} name]} {
- alertnote "Can't find app w/ sig '$sig'.\
- Try rebuilding your desktop or changing your helper apps."
- error ""
- }
- if {![file exists $name]} {
- alertnote "Sig '$sig' is mapped to '$name', which doesn't\
- exist. Try changing your helper apps."
- error ""
- }
- # Launch the app
- if {$in_front} {
- launch -f $name
- } else {
- launch $name
- }
- hook::callAll launch $sig
- return $name
- }
-
- # Switch to 'sig', launching if necesary
- proc app::launchFore {sig} {
- app::ensureRunning $sig 1
- }
-
- # Ensure that the app is at least running in the background.
- proc app::launchBack {sig} {
- app::ensureRunning $sig 0
- }
-
- proc app::launchAnyOfThese {sigs sig {prompt "Please locate the application:"}} {
- app::launchBackSigs $sigs $sig $prompt 0
- }
- proc app::launchElseTryThese {sigs sig {prompt "Please locate the application:"}} {
- app::launchBackSigs $sigs $sig $prompt 1
- }
-
- # Check to see if any of the 'sigs' is running. If so, return its name.
- # Otherwise, attempt to launch the file named by 'sig'.
- proc app::launchBackSigs {sigs sig {prompt "Please locate the application:"} {running_first 1} } {
- upvar \#0 $sig theSig
- if {$running_first || ![info exists theSig] || [catch {nameFromAppl [set theSig]}]} {
- app::setRunningSig $sigs $sig
- app::getSig $prompt $sig
- }
- return [app::launchBack [set theSig]]
- }
-
- proc app::getSig {prompt sig} {
- upvar \#0 $sig theSig
- if {[catch {nameFromAppl [set theSig]}]} {
- set theSig [getFileSig [getfile $prompt]]
- prefs::modified $sig
- }
- }
-
- proc app::setRunningSig {sigs sig} {
- upvar \#0 $sig theSig
- if {[app::isRunning $sigs name s]} {
- if {![info exists theSig] || ($s != [set theSig])} {
- set theSig $s
- prefs::modified $sig
- }
- return 1
- }
- return 0
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "app::runScript" --
- #
- # Generic run script handler. Will prompt for the location of your
- # application if necessary, run in fore/background, show a log of
- # the result etc. See latexComm.tcl or diffMode.tcl for examples
- # of the necessary array entries.
- #
- # 3 variables must be defined: ${op}Sig is a variable whose
- # value is the signature of the application the user has selected
- # to carry out this operation (or the path of an executable, if
- # 'exec' is possible), ${op}AppSignatures is an array of all
- # possible name/signature pairs currently known, and ${op}AppScripts
- # are the scripts for each of those signatures.
- #
- # 'flags' are additional flags to pass to the application
- # 'depth' says how many levels of hierarchy Alpha should backup
- # before calling the application for a given file. If depth is
- # not an integer, it can be the actual path prefix up to which
- # Alpha should backup. 'depth' isn't relevant to all applications
- #
- # Modified from original evalTeXScript in latex mode.
- #
- # 'runAppInBackground' now takes any of three values:
- # 0: run in foreground
- # 1: run in background if possible, but we want to capture the output
- # of the process, so we may need to run in foreground.
- # 2: force to run in background (and therefore ignore the output of
- # the process).
- #
- # The '1' value is useful for many calls such as diff, cvs, etc in
- # which on MacOS we will use apple-events and can therefore run in
- # the background, but on Unix/Windows we can't run with 'exec ... &'
- # because we won't be able to capture the result. Since these tools
- # are command line tools on Unix/Windows, running in the foreground is
- # effectively running in the background.
- # -------------------------------------------------------------------------
- ##
- proc app::runScript {opp prompt filename {runAppInBackground 0} {showLog 0} {flags ""} {depth ""} {isInDir 0}} {
- if {[llength $opp] > 1} {
- set sigIn [lindex $opp 0]
- set op [lindex $opp 1]
- global $sigIn
- set opVar "${sigIn}(${op}Sig)"
- } else {
- set op $opp
- global ${op}Sig
- set opVar "${op}Sig"
- }
- global ${op}AppSignatures ${op}AppScripts nonInteractiveApps
-
- set supportedApps [array names ${op}AppSignatures]
- set sigs ""
- foreach app $supportedApps { eval lappend sigs [set ${op}AppSignatures($app)] }
- set longPrompt "Please locate a $prompt."
- if { [catch {app::launchAnyOfThese $sigs $opVar $longPrompt} appname] } {
- error "bug in 'app::launchAnyOfThese' : $appname"
- }
- set sig [set $opVar]
- set quotedSig "'[string trim $sig {'}]'"
- if {!$runAppInBackground} { switchTo $quotedSig }
- if {[file exists $sig]} {
- global tcl_platform
- set stream 1
- # Windows Tcl 8.0 has some fileevent bugs
- if {$tcl_platform(platform) == "windows" && [info tclversion] < 8.1} {
- set stream 0
- }
- # Some apps we never wish to capture stdout/stderr
- if {[info exists nonInteractiveApps]} {
- if {[lsearch -exact $nonInteractiveApps $op] != -1} {
- set stream 0
- set runAppInBackground 2
- }
- }
- if {$stream && $showLog} {
- global mode
- set win [new -n "* $op log *" -m $mode -text "File: $filename\n" -shell 1]
- if {$filename != ""} {
- set olddir [pwd]
- if {$depth != ""} {
- if {[is::UnsignedInteger $depth]} {
- set path [file dirname $filename]
- set filename [file tail $filename]
- while {[incr $depth -1] >= 0} {
- # currently win/unix specific path delimiter
- set filename "[file tail $path]/$filename"
- set path [file dirname $path]
- }
- cd $path
- } else {
- cd $depth
- # $filename is assumed either to be a full
- # path or already backed up to the correct level.
- if {[file::pathStartsWith $filename $depth]} {
- set filename [string range $filename [expr {[string length $depth] +1}] end]
- }
- }
- } else {
- cd [file dirname $filename]
- set filename [file tail $filename]
- }
- set filename [eval file join [file split $filename]]
- app::setupInput "\"$sig\" $filename $flags" $win
- cd $olddir
- } else {
- app::setupInput "\"$sig\" [file tail $filename] $flags" $win
- }
- set res ""
- } else {
- # We need the output so we actually have to run 'in the foreground'.
- if {$runAppInBackground == 1} { set runAppInBackground 0 }
- if {$filename != ""} {
- set olddir [pwd]
- if {$isInDir} {
- cd $filename
- if {$runAppInBackground} {
- set err [catch {eval [list exec $sig] $flags &} res]
- } else {
- set err [catch {eval [list exec $sig] $flags} res]
- }
- cd $olddir
- } else {
- cd [file dirname $filename]
- if {$runAppInBackground} {
- set err [catch {eval [list exec $sig [file tail $filename]] $flags &} res]
- } else {
- set err [catch {eval [list exec $sig [file tail $filename]] $flags} res]
- }
- cd $olddir
- }
- } else {
- if {$runAppInBackground} {
- set err [catch {eval exec [list $sig] $flags &} res]
- } else {
- set err [catch {eval exec [list $sig] $flags} res]
- }
- }
- if {$runAppInBackground} {
- message "Application running in background."
- return
- }
- if {[expr {($showLog + $err) > 1}]} {
- global mode
- new -n "* $op log *" -m $mode -info "File: $filename\n$res"
- }
- if {$err} {
- beep
- message "Run completed abnormally."
- } else {
- message "Run completed successfully."
- }
- }
-
- return $res
- } else {
- foreach app $supportedApps {
- if {[lsearch -exact [set ${op}AppSignatures($app)] $sig] >= 0} {
- foreach script [set ${op}AppScripts($app)] {
- set res [eval $script]
- }
- return $res
- }
- }
- }
- beep
- alertnote "Sorry, no support for your $prompt."
- return
- }
-
- proc app::setupInput {cmd win} {
- global catSig
- app::getSig "Please find your 'cat' application" catSig
- insertText -w $win $cmd "\n"
- set pipe [open "| \"$catSig\"" r+]
- fconfigure $pipe -buffering none
- fileevent $pipe readable [list app::handleErrorInput $win $pipe 1]
- set output [open "|$cmd 2>@ $pipe" r]
- fileevent $output readable [list app::handleStdoutInput $win $output $pipe]
- }
-
- proc app::handleErrorInput {w f {err 1}} {
- set data [gets $f]
- if {[string length $data] > 0} {
- goto [maxPos -w $w]
- insertText -w $w $data "\n"
- update
- }
- }
-
- proc app::handleStdoutInput {w output err} {
- if {[eof $output]} {
- fileevent $output readable ""
- catch {close $output}
- fileevent $err readable ""
- #catch flush $err
- catch {close $err}
- goto [maxPos -w $w]
- insertText -w $w "\nDone\n"
- winReadOnly $w
- }
- # If this fails, the process must have finished, and the pipe closed.
- if {![catch {gets $output} data]} {
- if {[string length $data] > 0} {
- goto [maxPos -w $w]
- insertText -w $w $data "\n"
- update
- }
- }
- }
-
- proc app::handleInput {w f {err 0}} {
- # Delete handler if input was exhausted.
- if {[eof $f]} {
- fileevent $f readable {}
- close $f
- return
- }
-
- set data [read $f]
-
- if {[string length $data] > 0} {
- goto [maxPos -w $w]
- insertText -w $w $data
- }
- }
-
-
- ##
- # -------------------------------------------------------------------------
- #
- # "app::isRunning" --
- #
- # Is an app with one of the given sigs running. Set the global $sig
- # to the name of that thing if it is
- #
- # {"Finder" "MACS" 978944 182209 }
- #
- # Much improved by Vince to avoid scanning the processes list one at a
- # time.
- #
- # -------------------------------------------------------------------------
- ##
- proc app::isRunning {sigs {n ""} {s ""}} {
- if {$n != ""} {upvar $n name}
- if {$s != ""} {upvar $s sig}
- if {[info tclversion] < 8.0} {
- return [regexp "\"(\[^\"\]+)\" \"([join [quote::Regfind [quote::Regfind $sigs]] |])\" " \
- [processes] "" name sig]
- } else {
- global alpha::platform
- if {$alpha::platform == "alpha"} {
- foreach ss $sigs {
- foreach p [processes] {
- if {[lindex $p 1] == $ss} {
- set sig $ss
- set name [lindex $p 0]
- return 1
- }
- }
- }
- } else {
- foreach ss $sigs {
- if {[string length $ss] > 4 && [file exists $ss]} {
- set sig $ss
- set name $ss
- return 1
- }
- }
- }
- }
- return 0
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "app::registerMultiple" --
- #
- # Does the dirty work so a mode can use different icons for its menu
- # according to which application a particular user has selected for
- # that mode. The arguments are as follows:
- #
- # type - a prefix such as 'java' which is used to create variables
- # such as 'javaSig' 'javaMenu'
- # creators - the list of recognised creators (1st is default)
- # icons - the list of icon resources
- # menurebuild - the procedure which is used to rebuild the mode menu
- #
- # here's an example:
- #
- # app::registerMultiple java [list Javc WARZ] \
- # [list •140 •285] rebuildJavaMenu
- #
- # of course the rebuild procedure must use the correct icon like this:
- #
- # proc rebuildJavaMenu {} {
- # global javaMenu
- # menu -n $javaMenu -p javaMenuProc {
- # }
- # }
- #
- # Note: this procedure ensures the menu is created the first time it
- # is called.
- # --Version--Author------------------Changes-------------------------------
- # 1.0 <vince@santafe.edu> original
- # -------------------------------------------------------------------------
- ##
- proc app::registerMultiple {type creators icons menurebuild} {
- global ${type}Sig multiApp
- if {![info exists ${type}Sig]} {
- set ${type}Sig [lindex $creators 0]
- }
- set multiApp($type) [list $creators $icons $menurebuild]
- app::multiChanged ${type}
- trace variable ${type}Sig w [list app::multiChanged $type]
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "app::multiChanged" --
- #
- # Utility procedure used by the above. No need to call it manually.
- # -------------------------------------------------------------------------
- ##
- proc app::multiChanged {type args} {
- global ${type}Menu ${type}Sig multiApp
- # remove old menu
- catch {removeMenu [set ${type}Menu]}
- # update the icon according to signature
- set info $multiApp($type)
- if {[set i [lsearch -exact [lindex $info 0] [set ${type}Sig]]] == -1} {
- set i 0
- }
- set ${type}Menu [lindex [lindex $info 1] $i]
- # rebuild the menu
- eval [lindex $multiApp($type) 2]
- # insert the new menu
- insertMenu [set ${type}Menu]
- }
-
-
-
-
-
-